package scala.examples.tcpoly.idioms;

/*trait HOFunction1[from[_], to[_]] {
  def apply[x](a: from[x]): to[x]
}

trait TFunctor[m[_]]{type apply[a]=Functor[m, a]}
abstract class Applicative[m[_], a](implicit val toFunctor: HOFunction1[m, TFunctor[m]#apply]) { // encoding of m[_] <% Functor[m, _]
  def pure(x: a): m[a]
  
  val self: m[a]
  def *: [b](fun: m[a =>b]): m[b] // original second argument -> self
}

abstract class Monoid[a] {
  val identity: a
  
  val self: a // the left operand
  def op(y: a): a
}

// encoding of type Const[t][_] = t
// Const[t] --> Const[t]#apply
trait Const[t] { type apply[_] = t }

trait Idioms {
  implicit def MonoidIdiom[a](s: a)
               (implicit toMonoid: a => Monoid[a], toFunctor: HOFunction1[Const[a]#apply, TFunctor[Const[a]#apply]#apply])
               : Applicative[Const[a]#apply, a]
               = new Applicative[Const[a]#apply, a] {
    def pure(x: a) = x.identity

    val self: a = s // the idiomatic argument
    def *: [t](x: a): a = x op self
  }
}

trait Prod[m[_], n[_]] { type apply[a] = (m[a], n[a]) }

*/
/*trait Core {
  trait Env[v] extends (v => Int)
  
  sealed trait Exp[v]
  case class Var[v](v: v) extends Exp[v]
  case class Val(i: Int) extends Exp[Int]
  case class Add[v](a: Exp[v], b: Exp[v]) extends Exp[v]
}

object v1 extends Core {
  def eval[v](e: Exp[v])(g: Env[v]): Int = e match {
    case Var(x)    => g(x)
    case Val(i)    => i
    case Add(p, q) => eval(p)(g) + eval(q)(g)
  }
}

object withImplicits extends Core {
  def eval[v](e: Exp[v])(implicit g: Env[v]): Int = e match {
    case Var(x)    => g(x)
    case Val(i)    => i
    case Add(p, q) => eval(p) + eval(q)
  }
}

object withImplicits2 extends Core {
  implicit def eval[v](e: Exp[v])(implicit g: Env[v]): Int = e match {
    case Var(x)    => g(x)
    case Val(i)    => i
    case Add(p, q) => p + q
  }
}

*/